home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 16
/
Aminet 16 (1996)(GTI - Schatztruhe)[!][Dec 1996].iso
/
Aminet
/
misc
/
emu
/
QDOS2.lha
/
QLsource
/
ROMsrc
/
CLK
/
CLK_asm
Wrap
Text File
|
1995-07-25
|
12KB
|
548 lines
SECTION CLK
INCLUDE '/INC/QDOS_inc'
INCLUDE '/INC/AMIGA_inc'
INCLUDE '/INC/AMIGQDOS_inc'
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; CLK_asm - Clock routines
; - last modified 25/07/95
; All the necessary clock related sources, required to
; implement QDOS clock routines on the Amiga computer.
; Amiga-QDOS sources by Rainer Kowallik
; ...latest changes by Mark J Swift
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; ROM header
BASE:
dc.l $4AFB0001 ; ROM recognition code
dc.w 0
dc.w ROM_START-BASE
dc.b 0,32,'Amiga-QDOS CLOCK routines v1.12',$A
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; start of ROM code
ROM_START:
movem.l d0-d2/a0-a3,-(a7)
; --------------------------------------------------------------
; allocate memory for CLK patch variables
move.l #CV_LEN,d1
moveq #MT.ALCHP,d0
moveq #0,d2
trap #1
; --------------------------------------------------------------
; address of CLK patch variables
move.l a0,AV.CLKV
move.l a0,a3
; --------------------------------------------------------------
; enter supervisor mode and disable interrupts
trap #0
ori.w #$0700,sr ; disable interrupts
; --------------------------------------------------------------
; link a custom routine into RESET routine
lea AV.RSETlink,a1
lea CV.RSETlink(a3),a2
move.l (a1),(a2)
move.l a2,(a1)
lea MY_RSET(pc),a1
move.l a1,$04(a2)
; --------------------------------------------------------------
; link a custom routine into level 7 interrupt server
lea AV.LVL7link,a1
lea CV.LVL7link(a3),a2
move.l (a1),(a2)
move.l a2,(a1)
lea MY_LVL7(pc),a1
move.l a1,$04(a2)
; --------------------------------------------------------------
; link a custom routine into Trap #1 exception
lea AV.TRP1link,a1
lea CV.TRP1link(a3),a2
move.l (a1),(a2)
move.l a2,(a1)
lea MY_TRP1(pc),a1
move.l a1,$04(a2)
; --------------------------------------------------------------
; Read Amiga clock and set QDOS clock
bsr.s INIT_HW
andi.w #$D8FF,sr ; enable ints, enter user
ifd isA500
bne.s ADD_XINT ; skip if clock exists
lea CLK_MESS(pc),a1 ; start of message
suba.l a0,a0 ; output channel 0
move.w UT.MTEXT,a2
jsr (a2) ; print it
endif
; -------------------------------------------------------------
; link in external interrupt to act on blitter
ADD_XINT:
move.l AV.CLKV,a3
lea XINT_SERv(pc),a1 ; address of routine
lea CV.XINTLink(a3),a0
move.l a1,4(a0)
moveq #MT.LXINT,d0
trap #1
; --------------------------------------------------------------
ROM_EXIT:
movem.l (a7)+,d0-d2/a0-a3
rts
CLK_MESS:
dc.b 0,33,' clock initialised from AmigaDOS',10,0
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; subroutine to read AMIGA clock and initialise QDOS clock
INIT_HW:
movem.l d0-d3/a0/a3,-(a7)
ifd isA500
bsr INITCLK
move.l d1,d4 ; hardware clock into d4
bclr #7,CIAA_CRB ; next write is to counter
move.b #0,CIAA_EMSB ; reset event counter
move.b #0,CIAA_EMID
move.b #0,CIAA_ELSB
clr.b d1
WAITCLK1:
move.b d1,d2
moveq #-1,d3
WAITCLK2:
move.b CIAA_ELSB,D1 ; bits 0-7
cmp.b #75,D0
bge.s INIT_HW1 ; wait about 1.5 secs
cmp.b d1,d2
bne.s WAITCLK1
dbra d3,WAITCLK2 ; don't wait too long
INIT_HW1:
bsr INITCLK ; check clock again
move.l d1,d0
sub.l d4,d0
ble.s INIT_HW2 ; no difference, no clock
subq.l #3,d0 ; difference greater than 3?
bcs.s INIT_HW3 ; nope, clock functional
endif
INIT_HW2:
moveq #0,d0
move.l PC_CLOCK,d1 ; get date from QL h/w
INIT_HW3:
move.l d1,PC_CLOCK ; set date
move.b #%00000100,CIAA_ICR ; disable ALARM interrupt
bclr #7,CIAA_CRB ; next write is to counter
move.b #0,CIAA_EMSB ; reset event counter
move.b #0,CIAA_EMID
move.b #0,CIAA_ELSB
bset #7,CIAA_CRB ; next write is to ALARM
move.b #2,CIAA_EMSB ; alarm every hour - so
move.b #191,CIAA_EMID ; as to update clock from
move.b #32,CIAA_ELSB ; event counter.
move.b CIAA_ICR,d7 ; read & clear CIA-A ICR
or.b AV.CIAA_ICR,d7
bclr #2,d7 ; clear ALARM bit
move.b d7,AV.CIAA_ICR ; store for another program
move.w #%0000000000001000,INTREQ ; clear and enable
move.w #%1000000000001000,INTENA ; CIA-A interrupts
move.b #%10000100,CIAA_ICR ; enable ALARM interrupt
ori.b #%00000100,AV.CIAA_MSK ; take note of alarm
tst.l d0
movem.l (a7)+,d0-d3/a0/a3
rts
; --------------------------------------------------------------
ifd isA500
INITCLK:
moveq #0,d2 ; fetch year (i.e. 91)
move.b CLK_YYH,d2
andi.b #$0F,d2
mulu.w #10,d2
move.b CLK_YYL,d3
andi.b #$0F,d3
add.b d3,d2
cmpi.b #78,d2 ; years before 1978 should
bge.s INITCLK1 ; be read as 20xx i.e 2077
addi.b #100,d2
; --------------------------------------------------------------
INITCLK1:
subi.b #61,d2 ; relative to 1961
move.l d2,d0 ; make a copy
mulu.w #365,d2
move.l d2,d1 ; accumulate date in d1
; --------------------------------------------------------------
moveq #0,d2 ; fetch month
move.b CLK_MMH,d2
andi.b #$0F,d2
mulu.w #10,d2
move.b CLK_MML,d3
andi.b #$0F,d3
add.b d3,d2
divu.w #4,d0 ; test for leap year
swap d0
cmpi.w #3,d0 ; is it a leap year?
bne.s INITCLK2 ; ...no
cmpi.w #2,d2 ; is it after february?
ble.s INITCLK2 ; ...no
addq.l #1,d1 ; compensate for extra day
; --------------------------------------------------------------
INITCLK2:
clr.w d0
swap d0 ; clear high 16 bits of d0
add.l d0,d1 ; add in previous leap years
; --------------------------------------------------------------
subq.l #1,d2 ; month number now (0...11)
asl.w #1,d2 ; offset into table
lea DAYTBL(pc),a0
move.w 0(a0,d2.w),d2 ; cumulative total to d2
add.l d2,d1 ; add it to date
; --------------------------------------------------------------
moveq #0,d2 ; fetch day
move.b CLK_DDH,d2
andi.b #$0F,d2
mulu.w #10,d2
move.b CLK_DDL,d3
andi.b #$0F,d3
add.b d3,d2
subq.w #1,d2 ; compensate for day zero
add.l d2,d1 ; add it to date
; --------------------------------------------------------------
moveq #24,d0 ; convert days to hours
bsr MULT
moveq #0,d2 ; fetch hour
move.b CLK_HRH,d2
andi.b #$0F,d2
mulu.w #10,d2
move.b CLK_HRL,d3
andi.b #$0F,d3
add.b d3,d2
add.l d2,d1 ; add it to date
; --------------------------------------------------------------
moveq #60,d0 ; convert hours to minutes
bsr.s MULT
moveq #0,d2 ; fetch minute
move.b CLK_MNH,d2
andi.b #$0F,d2
mulu.w #10,d2
move.b CLK_MNL,d3
andi.b #$0F,d3
add.b d3,d2
add.l d2,d1 ; add it to date
; --------------------------------------------------------------
moveq #60,d0 ; convert minutes to secs
bsr.s MULT
moveq #0,d2 ; fetch seconds
move.b CLK_SCH,d2
andi.b #$0F,d2
mulu.w #10,d2
move.b CLK_SCL,d3
andi.b #$0F,d3
add.b d3,d2
add.l d2,d1 ; add it to date
rts
endif
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; table of cumulative totals of length of each month
DAYTBL:
dc.w 0,31,59,90,120,151,181,212,243,273,304,334
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; multiply 32 bit d1 by 16 bit d0 (assumes no overflow)
MULT:
move.l d1,d2 ; make copy
swap d1 ; multiply high word
mulu.w d0,d1
swap d1
clr.w d1
mulu.w d0,d2 ; multiply low word
add.l d2,d1
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Custom RSET routine to update the clock before a system reset
MY_RSET:
bsr UPDT_CLK
subq.l #4,a7
movem.l a3,-(a7)
move.l AV.CLKV,a3
move.l CV.RSETlink(a3),a3
move.l 4(a3),4(a7) ; address of next routine
movem.l (a7)+,a3
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Custom LVL7 routine to initialise hardware
MY_LVL7:
bsr INIT_HW
subq.l #4,a7
movem.l a3,-(a7)
move.l AV.CLKV,a3
move.l CV.LVL7link(a3),a3
move.l 4(a3),4(a7) ; address of next routine
movem.l (a7)+,a3
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; A patch to replace TRAP#1 calls to:
; MT_RCLCK (d0=$13), MT_SCLCK (d0=$14), MT_ACLCK (d0=$15)
MY_TRP1:
bsr.s INI_A5A6
cmp.b #MT.RCLCK,d0
beq.s MT_RCLCK
cmp.b #MT.SCLCK,d0
beq.s MT_SCLCK
cmp.b #MT.ACLCK,d0
beq.s MT_ACLCK
movem.l (a7)+,d7/a5/a6 ; restore registers
subq.l #4,a7
movem.l a3,-(a7)
move.l AV.CLKV,a3
move.l CV.TRP1link(a3),a3
move.l 4(a3),4(a7) ; address of next routine
movem.l (a7)+,a3
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; initialise A5 and A6 prior to performing a TRAP routine
INI_A5A6
SUBQ.L #8,A7
MOVE.L 8(A7),-(A7)
MOVEM.L D7/A5/A6,4(A7)
move.l a7,d7
andi.l #$FFFF8000,d7
move.l d7,a6 ; Calc address of sys vars
LEA 4(A7),A5 ; A5 points to saved
; Registers D7,A5,A6
MOVEQ #$7F,D7
AND.L D7,D0
RTS
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; TRAP #1 with D0=$13
; implement clock (CIA-A event counter)/50+PC_CLOCK
MT_RCLCK:
bsr UPDT_CLK
moveq #0,d0 ; no errors
bra.s TRAP1_X
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; TRAP #1 with D0=$14
MT_SCLCK:
move.l d1,PC_CLOCK ; use this as new offset
bclr #7,CIAA_CRB ; next write is to counter
move.b #0,CIAA_EMSB ; reset event counter
move.b #0,CIAA_EMID
move.b #0,CIAA_ELSB
moveq #0,d0 ; no errors
bra.s TRAP1_X
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; TRAP #1 with D0=$15
MT_ACLCK:
add.l d1,PC_CLOCK ; adjust increment offset
moveq #0,d0 ; no errors
; --------------------------------------------------------------
; exit from TRAP call
TRAP1_X movem.l (a7)+,d7/a5/a6 ; exit from exception
rte
; --------------------------------------------------------------
UPDT_CLK:
MOVEQ.L #0,D1
MOVE.B CIAA_EMSB,D1 ; read bits 16-23
LSL.L #8,D1
MOVE.B CIAA_EMID,D1 ; bits 8-15
LSL.L #8,D1
MOVE.B CIAA_ELSB,D1 ; bits 0-7
DIVU #5000,D1 ; 100 seconds
MOVEQ #0,D0
MOVE.W D1,D0 ; get quotient
MULU #100,D0 ; get seconds so far
SWAP D1
AND.L #$FFFF,D1 ; get remainder
DIVU #50,D1 ; get seconds
bclr #7,CIAA_CRB ; next write is to counter
move.b #0,CIAA_EMSB
move.b #0,CIAA_EMID
move.b #0,CIAA_ELSB
;swap d1 ; get ticks remaining
;move.b d1,CIAA_ELSB ; restart counter
;swap d1
AND.L #$FFFF,D1 ; get quotient
ADD.L D0,D1 ; seconds complete
add.l PC_CLOCK,d1 ; add offset for actual day
; and time
move.l d1,PC_CLOCK ; update QL h/w
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; external interrupt server
XINT_SERv:
movem.l d7/a0,-(a7)
move.w INTENAR,d7 ; read interrupt enable reg
btst #3,d7 ; branch if ints not on
beq XINT_OTHer
move.w INTREQR,d7 ; read interrupt request reg
btst #3,d7 ; branch if from CIA-A or
bne CIAA_SERv ; expansion ports
; --------------------------------------------------------------
; otherwise let another external interrupt server handle it
XINT_OTHer:
movem.l (a7)+,d7/a0
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Interrupt from CIA-A or expansion port
CIAA_SERv:
move.b CIAA_ICR,d7 ; read CIA-A ICR
or.b AV.CIAA_ICR,d7
move.b d7,AV.CIAA_ICR ; store for another program
bclr #2,d7 ; (ALARM bit=1)
beq XINT_OTHer ; no
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; External interrupt server for acting on event counter alarm
; (CIAA ALARM bit=1).
ALRM_SERv:
move.b d7,AV.CIAA_ICR
and.b AV.CIAA_MSK,d7 ; don't clear INTREQ if
bne.s ALRM_0 ; other CIAA ints occured
move.w #%0000000000001000,INTREQ ; clear interrupts
; -------------------------------------------------------------
ALRM_0:
bsr UPDT_CLK ; update clock
; -------------------------------------------------------------
XINT_EXIt:
bra XINT_OTHer
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
END